package ro.ubbcluj.cs.validation.framework.tags;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ro.ubbcluj.cs.validation.framework.core.ParameterName;
import ro.ubbcluj.cs.validation.framework.core.ValidationRuleType;

public class ValidatorTag extends TagSupport {

	private static final long serialVersionUID = 989283762593015633L;
	private Logger log = LoggerFactory.getLogger(ValidatorTag.class);
	
	/**
	 * The type of the validator (text,	word, digit, number, date, email, url, file)
	 */
	private String type;
	/**
	 * If the value true than the user must fill the field (true, false)
	 */
	private Boolean required;
	/**
	 * The minimum length of field (number of characters)
	 */
	private Integer minlength;
	/**
	 * The maximum length of field (number of characters)
	 */
	private Integer maxlength;
	/**
	 * The number format, just for number type validator (int, real)
	 */
	private String numberformat;
	/**
	 * The minimum value, just for number type validator (number)
	 */
	private String minvalue;
	/**
	 * The maximum value, just for number type validator (number)
	 */
	private String maxvalue;
	/**
	 * The patter for date, just for date type validator (ex: yyyy.MM.dd)
	 */
	private String pattern;
	/**
	 * Check if the field value is before the specified date, just for date type validator (java.util.Calendar)
	 */
	private Calendar before;
	/**
	 * Check if the field value is after the specified date, just for date type validator (java.util.Calendar)
	 */
	private Calendar after;
	/**
	 * Check if the field value is a weekday, just for date type validator (boolean)
	 */
	private Boolean weekday;
	/**
	 * Check if the field value is a day of weekend, just for date type validator (boolean)
	 */
	private Boolean weekend;
	/**
	 * Check if the uploaded file extension equals with the specified extension, just for date type validator (doc, pdf, jpg, ...)
	 */
	private String extension;
	
	@Override
	public int doStartTag() throws JspException {
		if (this.getParent() instanceof GeneralInputTag) {
			if (StringUtils.isNotEmpty(type)){
				try {
					((GeneralInputTag)this.getParent()).addValidationRule(ValidationRuleType.valueOf(type), getParameters());
				} catch (IllegalArgumentException e) {
					log.error("Illegal validator type ("+type+")!");
				}
			} else {
				log.error("The type attribute is empty!");
			}			
		} else {
			log.error("Wrong place for the validator tag! Validator tag can be put only into input tag.");
		}
		release();
		return EVAL_PAGE;
	}
	
	private Map<ParameterName, String> getParameters(){
		Map<ParameterName, String> parameter = new HashMap<ParameterName, String>();
		if (required != null){
			parameter.put(ParameterName.required, Boolean.valueOf(required).toString());
		}
		if (minlength != null) {
			try {
				parameter.put(ParameterName.minlength, Integer.valueOf(minlength).toString());
			} catch (NumberFormatException e) {
				log.error("Illegal minlength argument ("+minlength+")!");
			}
		}
		if (maxlength != null) {
			try {
				parameter.put(ParameterName.maxlength, Integer.valueOf(maxlength).toString());
			} catch (NumberFormatException e) {
				log.error("Illegal maxlength argument ("+maxlength+")!");
			}	
		}
		if (numberformat != null){
			if (numberformat.equalsIgnoreCase("int") || numberformat.equalsIgnoreCase("real")) {
				parameter.put(ParameterName.numberformat, String.valueOf(numberformat));
			} else {
				log.error("Illegal numberformat argument ("+numberformat+")!");
			}
		}
		if (minvalue != null) {
			if (numberformat == null || numberformat.equalsIgnoreCase("int")){
				try {
					parameter.put(ParameterName.minvalue, Integer.valueOf(minvalue).toString());
				} catch (NumberFormatException e) {
					log.error("Illegal minvalue argument ("+minvalue+")!");
				}	
			} else {
				try {
					parameter.put(ParameterName.minvalue, Double.valueOf(minvalue).toString());
				} catch (NumberFormatException e) {
					log.error("Illegal minvalue argument ("+minvalue+")!");
				}	
			}
		}
		if (maxvalue != null) {
			if (numberformat == null || numberformat.equalsIgnoreCase("int")){
				try {
					parameter.put(ParameterName.maxvalue, Integer.valueOf(maxvalue).toString());
				} catch (NumberFormatException e) {
					log.error("Illegal maxvalue argument ("+maxvalue+")!");
				}	
			} else {
				try {
					parameter.put(ParameterName.maxvalue, Double.valueOf(maxvalue).toString());
				} catch (NumberFormatException e) {
					log.error("Illegal maxvalue argument ("+maxvalue+")!");
				}	
			}
		}
		if (pattern != null) {
			parameter.put(ParameterName.pattern, pattern);
		}
		if (before != null) {
			if (before instanceof Calendar) {
				if (pattern != null) {
					parameter.put(ParameterName.before, new SimpleDateFormat(pattern).format(before.getTime()));
				} else {
					log.error("Empty pattern argument!");
				}				
			} else {
				log.error("Illegal before argument ("+before+")!");
			}
		}
		if (after != null) {
			if (after instanceof Calendar) {
				if (pattern != null) {
					parameter.put(ParameterName.after, new SimpleDateFormat(pattern).format(after.getTime()));
				} else {
					log.error("Empty pattern argument!");
				}				
			} else {
				log.error("Illegal after argument ("+after+")!");
			}
		}
		if (weekday != null) {
			parameter.put(ParameterName.weekday, Boolean.valueOf(weekday).toString());
		}
		if (weekend != null) {
			parameter.put(ParameterName.weekend, Boolean.valueOf(weekend).toString());
		}
		if (extension != null) {
			parameter.put(ParameterName.extension, extension);
		}
		return parameter;
	}

	public final String getType() {
		return type;
	}

	public final void setType(String type) {
		this.type = type;
	}
	
	public final Boolean getRequired() {
		return required;
	}

	public final void setRequired(Boolean required) {
		this.required = required;
	}

	public final Integer getMinlength() {
		return minlength;
	}

	public final void setMinlength(Integer minlength) {
		this.minlength = minlength;
	}

	public final Integer getMaxlength() {
		return maxlength;
	}

	public final void setMaxlength(Integer maxlength) {
		this.maxlength = maxlength;
	}

	public final String getNumberformat() {
		return numberformat;
	}

	public final void setNumberformat(String numberformat) {
		this.numberformat = numberformat;
	}

	public final String getMinvalue() {
		return minvalue;
	}

	public final void setMinvalue(String minvalue) {
		this.minvalue = minvalue;
	}

	public final String getMaxvalue() {
		return maxvalue;
	}

	public final void setMaxvalue(String maxvalue) {
		this.maxvalue = maxvalue;
	}

	public final String getPattern() {
		return pattern;
	}

	public final void setPattern(String pattern) {
		this.pattern = pattern;
	}

	public final Calendar getBefore() {
		return before;
	}

	public final void setBefore(Calendar before) {
		this.before = before;
	}

	public final Calendar getAfter() {
		return after;
	}

	public final void setAfter(Calendar after) {
		this.after = after;
	}

	public final Boolean getWeekday() {
		return weekday;
	}

	public final void setWeekday(Boolean weekday) {
		this.weekday = weekday;
	}

	public final Boolean getWeekend() {
		return weekend;
	}

	public final void setWeekend(Boolean weekend) {
		this.weekend = weekend;
	}

	public final String getExtension() {
		return extension;
	}

	public final void setExtension(String extension) {
		this.extension = extension;
	}

	@Override
	public void release() {
		super.release();
		this.required = null;
		this.minlength = null;
		this.maxlength = null;
		this.numberformat = null;
		this.minvalue = null;
		this.maxvalue = null;
		this.pattern = null;
		this.before = null;
		this.after = null;
		this.weekday = null;
		this.weekend = null;
		this.extension = null;
	}
}
